use crate::audio_device::{AudioDeviceInfo, AudioStreamConfig};
use crate::audio_manager::{AudioDevices, AudioLevels, AudioManager};
use crate::call_history::{CallHistoryFilter, CallHistoryManager, CallRecord};
use crate::call_manager::CallManager;
use crate::config_manager::{AppConfig, ConfigManager};
use crate::sip_manager::{ConnectionTestResult, NetworkStatus, RegistrationStatus, SipConfig, SipManager, TransportType};
use std::sync::Arc;
use tauri::State;

pub struct AppState {
    pub sip_manager: Arc<SipManager>,
    pub call_manager: Arc<CallManager>,
    pub audio_manager: Arc<AudioManager>,
    pub config_manager: Arc<ConfigManager>,
    pub call_history_manager: Arc<CallHistoryManager>,
}

// SIP Account Management Commands
#[tauri::command]
pub async fn login(
    config: SipConfig,
    state: State<'_, AppState>,
) -> Result<(), String> {
    state.sip_manager.login(config.clone()).await
        .map_err(|e| e.to_string())?;
    
    state.config_manager.save_sip_config(config).await
        .map_err(|e| e.to_string())?;
    
    Ok(())
}

#[tauri::command]
pub async fn logout(
    state: State<'_, AppState>,
) -> Result<(), String> {
    state.sip_manager.logout().await
        .map_err(|e| e.to_string())?;
    
    state.config_manager.clear_sip_config().await
        .map_err(|e| e.to_string())?;
    
    Ok(())
}

#[tauri::command]
pub async fn get_registration_status(
    state: State<'_, AppState>,
) -> Result<RegistrationStatus, String> {
    Ok(state.sip_manager.get_registration_status().await)
}

#[tauri::command]
pub async fn test_connection(
    server: String,
    port: u16,
    transport: TransportType,
    state: State<'_, AppState>,
) -> Result<ConnectionTestResult, String> {
    state.sip_manager.test_connection(server, port, transport).await
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn get_network_status(
    state: State<'_, AppState>,
) -> Result<NetworkStatus, String> {
    Ok(state.sip_manager.get_network_status().await)
}

#[tauri::command]
pub async fn get_retry_count(
    state: State<'_, AppState>,
) -> Result<u32, String> {
    Ok(state.sip_manager.get_retry_count().await)
}

#[tauri::command]
pub async fn get_max_retries(
    state: State<'_, AppState>,
) -> Result<u32, String> {
    Ok(state.sip_manager.get_max_retries())
}

#[tauri::command]
pub async fn force_retry_registration(
    state: State<'_, AppState>,
) -> Result<(), String> {
    state.sip_manager.force_retry_registration().await
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn get_last_error(
    state: State<'_, AppState>,
) -> Result<Option<String>, String> {
    Ok(state.sip_manager.get_last_error().await)
}

#[tauri::command]
pub async fn get_auth_failure_count(
    state: State<'_, AppState>,
) -> Result<u32, String> {
    Ok(state.sip_manager.get_auth_failure_count().await)
}

#[tauri::command]
pub async fn get_max_auth_failures(
    state: State<'_, AppState>,
) -> Result<u32, String> {
    Ok(state.sip_manager.get_max_auth_failures())
}

#[tauri::command]
pub async fn reset_auth_failures(
    state: State<'_, AppState>,
) -> Result<(), String> {
    state.sip_manager.reset_auth_failures().await;
    Ok(())
}

#[tauri::command]
pub async fn is_authentication_locked(
    state: State<'_, AppState>,
) -> Result<bool, String> {
    Ok(state.sip_manager.is_authentication_locked().await)
}

// Call Management Commands
#[tauri::command]
pub async fn make_call(
    number: String,
    state: State<'_, AppState>,
) -> Result<String, String> {
    let call_id = state.call_manager.make_call(number, state.sip_manager.clone(), state.audio_manager.clone()).await
        .map_err(|e| e.to_string())?;
    
    // Start audio stream for the call
    state.audio_manager.start_audio_stream(&call_id).await
        .map_err(|e| e.to_string())?;
    
    Ok(call_id)
}

#[tauri::command]
pub async fn simulate_incoming_call(
    caller_number: String,
    caller_name: Option<String>,
    state: State<'_, AppState>,
) -> Result<String, String> {
    let call_id = state.call_manager.handle_incoming_call(caller_number, caller_name).await;
    Ok(call_id)
}

#[tauri::command]
pub async fn answer_call(
    call_id: String,
    state: State<'_, AppState>,
) -> Result<(), String> {
    state.call_manager.answer_call(call_id.clone()).await
        .map_err(|e| e.to_string())?;
    
    // Start audio stream for the call
    state.audio_manager.start_audio_stream(&call_id).await
        .map_err(|e| e.to_string())?;
    
    Ok(())
}

#[tauri::command]
pub async fn reject_call(
    call_id: String,
    state: State<'_, AppState>,
) -> Result<(), String> {
    state.call_manager.reject_call(call_id.clone()).await
        .map_err(|e| e.to_string())?;
    
    // Stop audio stream for the call
    state.audio_manager.stop_audio_stream(&call_id).await
        .map_err(|e| e.to_string())?;
    
    Ok(())
}

#[tauri::command]
pub async fn hangup_call(
    call_id: String,
    state: State<'_, AppState>,
) -> Result<(), String> {
    state.call_manager.hangup_call(call_id.clone()).await
        .map_err(|e| e.to_string())?;
    
    // Stop audio stream for the call
    state.audio_manager.stop_audio_stream(&call_id).await
        .map_err(|e| e.to_string())?;
    
    Ok(())
}

#[tauri::command]
pub async fn mute_call(
    call_id: String,
    muted: bool,
    state: State<'_, AppState>,
) -> Result<(), String> {
    state.call_manager.mute_call(call_id, muted).await
        .map_err(|e| e.to_string())?;
    
    state.audio_manager.set_muted(muted).await;
    
    Ok(())
}

#[tauri::command]
pub async fn get_active_calls(
    state: State<'_, AppState>,
) -> Result<std::collections::HashMap<String, crate::call_manager::CallInfo>, String> {
    Ok(state.call_manager.get_active_calls().await)
}

#[tauri::command]
pub async fn get_call_info(
    call_id: String,
    state: State<'_, AppState>,
) -> Result<Option<crate::call_manager::CallInfo>, String> {
    Ok(state.call_manager.get_call_info(&call_id).await)
}

#[tauri::command]
pub async fn cancel_incoming_call_timeout(
    call_id: String,
    state: State<'_, AppState>,
) -> Result<(), String> {
    state.call_manager.cancel_incoming_call_timeout(&call_id).await;
    Ok(())
}

#[tauri::command]
pub async fn handle_remote_hangup(
    call_id: String,
    state: State<'_, AppState>,
) -> Result<(), String> {
    state.call_manager.handle_remote_hangup(call_id.clone()).await
        .map_err(|e| e.to_string())?;
    
    // Stop audio stream for the call
    state.audio_manager.stop_audio_stream(&call_id).await
        .map_err(|e| e.to_string())?;
    
    Ok(())
}

#[tauri::command]
pub async fn get_call_quality_metrics_from_call_manager(
    call_id: String,
    state: State<'_, AppState>,
) -> Result<Option<crate::call_manager::CallQualityMetrics>, String> {
    Ok(state.call_manager.get_call_quality_metrics(&call_id).await)
}

// Audio Device Management Commands
#[tauri::command]
pub async fn get_audio_devices(
    state: State<'_, AppState>,
) -> Result<AudioDevices, String> {
    state.audio_manager.get_audio_devices().await
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn set_audio_device(
    input_device: Option<String>,
    output_device: Option<String>,
    state: State<'_, AppState>,
) -> Result<(), String> {
    state.audio_manager.set_audio_device(input_device, output_device).await
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn get_audio_levels(
    state: State<'_, AppState>,
) -> Result<AudioLevels, String> {
    Ok(state.audio_manager.get_audio_levels().await)
}

#[tauri::command]
pub async fn get_detailed_audio_devices(
    state: State<'_, AppState>,
) -> Result<Vec<AudioDeviceInfo>, String> {
    state.audio_manager.get_detailed_audio_devices().await
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn set_audio_stream_config(
    config: AudioStreamConfig,
    state: State<'_, AppState>,
) -> Result<(), String> {
    state.audio_manager.set_stream_config(config).await
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn get_audio_stream_config(
    state: State<'_, AppState>,
) -> Result<AudioStreamConfig, String> {
    Ok(state.audio_manager.get_stream_config().await)
}

#[tauri::command]
pub async fn update_audio_levels(
    input_level: f32,
    output_level: f32,
    state: State<'_, AppState>,
) -> Result<(), String> {
    state.audio_manager.update_audio_levels(input_level, output_level).await;
    Ok(())
}

// Enhanced Audio Stream Commands
#[tauri::command]
pub async fn create_audio_stream_with_quality(
    call_id: String,
    settings: crate::audio_stream::AudioStreamSettings,
    quality_settings: crate::audio_stream::AudioQualitySettings,
    state: State<'_, AppState>,
) -> Result<(), String> {
    state.audio_manager.create_audio_stream_with_quality(call_id, settings, quality_settings).await
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn set_stream_quality_settings(
    call_id: String,
    quality_settings: crate::audio_stream::AudioQualitySettings,
    state: State<'_, AppState>,
) -> Result<(), String> {
    state.audio_manager.set_stream_quality_settings(&call_id, quality_settings).await
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn get_stream_quality_settings(
    call_id: String,
    state: State<'_, AppState>,
) -> Result<Option<crate::audio_stream::AudioQualitySettings>, String> {
    Ok(state.audio_manager.get_stream_quality_settings(&call_id).await)
}

#[tauri::command]
pub async fn get_call_quality_metrics(
    call_id: String,
    state: State<'_, AppState>,
) -> Result<Option<crate::audio_stream::AudioQualityMetrics>, String> {
    Ok(state.audio_manager.get_call_quality_metrics(&call_id).await)
}

#[tauri::command]
pub async fn process_incoming_rtp(
    _call_id: String,
    rtp_data: Vec<u8>,
    _state: State<'_, AppState>,
) -> Result<(), String> {
    // Parse RTP packet from raw data
    // This is a simplified implementation - in production, use proper RTP parsing
    if rtp_data.len() < 12 {
        return Err("Invalid RTP packet size".to_string());
    }
    
    // Create a basic RTP packet structure
    // In production, use proper RTP packet parsing from the rtp crate
    let payload_type = rtp_data[1] & 0x7F;
    let sequence_number = u16::from_be_bytes([rtp_data[2], rtp_data[3]]);
    let timestamp = u32::from_be_bytes([rtp_data[4], rtp_data[5], rtp_data[6], rtp_data[7]]);
    let ssrc = u32::from_be_bytes([rtp_data[8], rtp_data[9], rtp_data[10], rtp_data[11]]);
    let payload = rtp_data[12..].to_vec();
    
    // For now, create a mock RTP packet since EZK RtpPacket doesn't have a simple constructor
    // TODO: Implement proper RTP packet parsing when integrating with EZK RTC library
    log::debug!("Processing RTP packet: PT={}, Seq={}, TS={}, SSRC={}, Len={}", 
        payload_type, sequence_number, timestamp, ssrc, payload.len());
    
    // Skip actual RTP processing for now
    return Ok(());
    
    // Actual RTP processing will be implemented when EZK RTC integration is complete
}

#[tauri::command]
pub async fn get_outgoing_rtp(
    call_id: String,
    _state: State<'_, AppState>,
) -> Result<Option<Vec<u8>>, String> {
    // TODO: Implement RTP packet retrieval when EZK RTC integration is complete
    log::debug!("Getting outgoing RTP for call: {}", call_id);
    Ok(None)
}

#[tauri::command]
pub async fn get_active_audio_streams(
    state: State<'_, AppState>,
) -> Result<Vec<String>, String> {
    Ok(state.audio_manager.get_active_audio_streams().await)
}

// Configuration Management Commands
#[tauri::command]
pub async fn load_config(
    state: State<'_, AppState>,
) -> Result<AppConfig, String> {
    state.config_manager.load_config().await
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn save_config(
    config: AppConfig,
    state: State<'_, AppState>,
) -> Result<(), String> {
    state.config_manager.save_config(&config).await
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn export_config(
    state: State<'_, AppState>,
) -> Result<String, String> {
    state.config_manager.export_config().await
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn import_config(
    base64_data: String,
    state: State<'_, AppState>,
) -> Result<(), String> {
    state.config_manager.import_config(&base64_data).await
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn config_exists(
    state: State<'_, AppState>,
) -> Result<bool, String> {
    Ok(state.config_manager.config_exists())
}// C
// Call History Management Commands
#[tauri::command]
pub async fn get_call_history(
    filter: Option<CallHistoryFilter>,
    state: State<'_, AppState>,
) -> Result<Vec<CallRecord>, String> {
    state.call_history_manager.get_call_history(filter).await
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn clear_call_history(
    state: State<'_, AppState>,
) -> Result<(), String> {
    state.call_history_manager.clear_call_history().await
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn get_call_count(
    state: State<'_, AppState>,
) -> Result<u32, String> {
    state.call_history_manager.get_call_count().await
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn delete_call_record(
    call_id: String,
    state: State<'_, AppState>,
) -> Result<bool, String> {
    state.call_history_manager.delete_call_record(&call_id).await
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn get_recent_numbers(
    limit: u32,
    state: State<'_, AppState>,
) -> Result<Vec<String>, String> {
    state.call_history_manager.get_recent_numbers(limit).await
        .map_err(|e| e.to_string())
}

#[tauri::command]
pub async fn make_call_from_history(
    number: String,
    state: State<'_, AppState>,
) -> Result<String, String> {
    // This is the same as make_call but specifically for calls initiated from history
    let call_id = state.call_manager.make_call(number, state.sip_manager.clone(), state.audio_manager.clone()).await
        .map_err(|e| e.to_string())?;
    
    // Start audio stream for the call
    state.audio_manager.start_audio_stream(&call_id).await
        .map_err(|e| e.to_string())?;
    
    Ok(call_id)
}